package com.coalmine.api.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coalmine.api.domain.ApiStat;
import com.coalmine.api.mapper.ApiStatMapper;
import com.coalmine.api.service.IApiStatService;
import com.coalmine.common.constant.CacheConstants;
import com.coalmine.common.core.redis.RedisCache;
import com.coalmine.common.utils.DateUtils;
import com.coalmine.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ApiStatServiceImpl extends ServiceImpl<ApiStatMapper, ApiStat> implements IApiStatService {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ApiStatMapper apiStatMapper;

    @Override
    public List<ApiStat> statByDay(String day) {
        List<ApiStat> historyList = apiStatMapper.statByDay(day);
        List<ApiStat> currentList = getCurrentStat();
        if (historyList.size() == 0) {
            return currentList;
        }
        if (currentList.size() == 0) {
            return historyList;
        }
        Map<String, Long> curApiSuccessMap = currentList.stream()
                .collect(Collectors.toMap(ApiStat::getApiId, ApiStat::getSuccessTimes));
        Map<String, Long> curApiFailureMap = currentList.stream()
                .collect(Collectors.toMap(ApiStat::getApiId, ApiStat::getSuccessTimes));
        historyList.stream().forEach(h -> {
            if (curApiSuccessMap.containsKey(h.getApiId())) {
                h.setSuccessTimes(h.getSuccessTimes() + curApiSuccessMap.get(h.getApiId()));
            }
            if (curApiFailureMap.containsKey(h.getApiId())) {
                h.setFailureTimes(h.getFailureTimes() + curApiFailureMap.get(h.getApiId()));
            }
        });
        return historyList;
    }

    @Override
    public List<ApiStat> statByUser() {
        return apiStatMapper.statByUser();
    }

    @Override
    public ApiStat statByApiUser(String apiId) {
        return getStat(apiId);
    }

    @Override
    public List<ApiStat> statByDayRange(String startDay, String endDay) {
        List<ApiStat> historyList = apiStatMapper.statByDayRange(startDay, endDay);
        List<ApiStat> currentList = getCurrentStat();
        if (historyList.size() == 0) {
            return currentList;
        }
        if (currentList.size() == 0) {
            return historyList;
        }
        historyList.addAll(currentList);
        return historyList;
    }

    @Override
    public List<ApiStat> statByMonth() {
        List<ApiStat> historyList = apiStatMapper.statByMonth();
        List<ApiStat> currentList = getCurrentStat();
        currentList.stream().forEach(c -> {
            c.setDay(c.getDay().substring(0, 6));
        });
        if (historyList.size() == 0) {
            return currentList;
        }
        if (currentList.size() == 0) {
            return historyList;
        }
        Long currentSuccessTimes = currentList.stream().mapToLong(ApiStat::getSuccessTimes).sum();
        Long currentFailureTimes = currentList.stream().mapToLong(ApiStat::getFailureTimes).sum();
        historyList.stream().forEach(h -> {
            if (DateUtils.dateTime().startsWith(h.getDay())) {
                h.setSuccessTimes(h.getSuccessTimes() + currentSuccessTimes);
                h.setFailureTimes(h.getFailureTimes() + currentFailureTimes);
            }
        });
        return historyList;
    }

    public ApiStat getStat(String apiId) {
        ApiStat stat = new ApiStat();
        ApiStat historyStat = getHistoryStat(apiId);
        ApiStat currentStat = getCurrentStat(apiId);
        stat.setSuccessTimes(currentStat.getSuccessTimes() + historyStat.getSuccessTimes());
        stat.setFailureTimes(currentStat.getFailureTimes() + currentStat.getFailureTimes());
        return stat;
    }

    private ApiStat getCurrentStat(String apiId) {
        String day = DateUtils.dateTime();
        String cacheKey = CacheConstants.DATE_API_USER_STAT + ":" + day + ":" + apiId;
        ApiStat result = redisCache.getCacheObject(cacheKey);
        if (StringUtils.isNull(result)) {
            String cacheKeyPattern = CacheConstants.DATE_API_USER_STAT + ":" + day + ":" + apiId + ":*";
            Collection<String> resultList = redisCache.keys(cacheKeyPattern);
            return resultList.size() == 0 ? new ApiStat()
                    : redisCache.getCacheObject(resultList.stream().findFirst().get());
        } else {
            return result;
        }
    }

    private ApiStat getHistoryStat(String apiId) {
        List<ApiStat> apiStats = statByUser();
        if (apiStats.size() == 0) {
            return new ApiStat();
        }
        return apiStats.stream()
                .filter(s -> s.getApiId().equals(apiId))
                .findAny()
                .orElse(new ApiStat());
    }

    private List<ApiStat> getCurrentStat() {
        String day = DateUtils.dateTime();
        String cacheKeyPattern = CacheConstants.DATE_API_USER_STAT + ":" + day + ":*";
        Collection<String> result = redisCache.keys(cacheKeyPattern);
        List<ApiStat> statList = new ArrayList<>();
        result.stream().forEach(s -> {
            ApiStat value = redisCache.getCacheObject(s);
            statList.add(value);
        });
        return statList;
    }
}
